package cn.dglydrpy.fundmanagement.controller;

import cn.dglydrpy.fundmanagement.service.IFundService;
import cn.dglydrpy.fundmanagement.service.dto.FundDto;
import cn.dglydrpy.fundmanagement.service.dto.FundSearchBean;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.util.List;

@RestController
@RequestMapping("/api/funds")
public class FundController {
    
    private static final Logger logger = LoggerFactory.getLogger(FundController.class);

    @Autowired
    private IFundService fundService;

    @PostMapping("/addFund")
    public void addFund(@RequestBody FundDto fundDto) {
        fundService.saveFund(fundDto);
    }

    @PostMapping("/updateFund")
    public void updateFund(@RequestBody FundDto fundDto) {
        fundService.updateFund(fundDto);
    }

    @PostMapping("/deleteFund/{id}")
    public void deleteFund(@PathVariable Long id) {
        logger.info("收到删除基金请求: fundId={}", id);
        fundService.deleteFund(id);
        logger.info("基金删除成功: fundId={}", id);
    }
    
    @GetMapping("/{id}")
    public FundDto getFundById(@PathVariable Long id) {
        FundDto fundDto = fundService.getFundById(id);
        return fundDto;
    }

    @GetMapping("/getFundsByConditions")
    public Page<FundDto> getFundsByConditions(
            @RequestParam(required = false) String fundCode,
            @RequestParam(required = false) String fundName,
            @RequestParam(required = false) String fundType,
            @RequestParam(required = false) String subType,
            @RequestParam(defaultValue = "1") int pageNo,
            @RequestParam(defaultValue = "10") int pageSize,
            @RequestParam(required = false) String sortField,
            @RequestParam(required = false) String sortOrder) {
        
        logger.info("收到条件查询基金请求: fundCode={}, fundName={}, fundType={}, subType={}, pageNo={}, pageSize={}, sortField={}, sortOrder={}", 
                   fundCode, fundName, fundType, subType, pageNo, pageSize, sortField, sortOrder);
        
        FundSearchBean fundSearchBean = new FundSearchBean();
        fundSearchBean.setFundCode(fundCode);
        fundSearchBean.setFundName(fundName);
        fundSearchBean.setFundType(fundType);
        fundSearchBean.setSubType(subType);

        Page<FundDto> result = fundService.getFundsByConditions(fundSearchBean, pageNo, pageSize, sortField, sortOrder);
        logger.info("条件查询基金完成: 总记录数={}, 总页数={}, 当前页={}, 每页大小={}", 
                   result.getTotal(), result.getPages(), result.getCurrent(), result.getSize());
        return result;
    }


    @PostMapping("/sync")
    public void fetchAndSaveFundData() {
        logger.info("收到同步标的净值数据请求");
        fundService.fetchAndSaveFundData();
        logger.info("标的净值数据同步完成!");
    }

    // 导出
    @GetMapping("/export")
    public void exportFundData(@RequestParam(required = false) String fundCode,
                               @RequestParam(required = false) String fundName,
                               @RequestParam(required = false) String fundType,
                               @RequestParam(required = false) String subType,
                               @RequestParam(required = false) String sortField,
                               @RequestParam(required = false) String sortOrder,
                               HttpServletResponse response) {
        
        logger.info("收到导出基金数据请求: fundCode={}, fundName={}, fundType={}, subType={}, sortField={}, sortOrder={}", 
                   fundCode, fundName, fundType, subType, sortField, sortOrder);

        FundSearchBean fundSearchBean = new FundSearchBean();
        fundSearchBean.setFundCode(fundCode);
        fundSearchBean.setFundName(fundName);
        fundSearchBean.setFundType(fundType);
        fundSearchBean.setSubType(subType);

        // 获取所有符合条件的数据，不分页
        List<FundDto> allFunds = fundService.getAllFundsByConditions(fundSearchBean, sortField, sortOrder);
        logger.info("获取到{}条基金数据用于导出", allFunds.size());

        // 创建Excel工作簿
        Workbook workbook = new XSSFWorkbook();
        Sheet sheet = workbook.createSheet("Funds");

        // 创建表头
        Row headerRow = sheet.createRow(0);
        String[] headers = {"基金代码", "基金名称", "标的类型", "标的子类型", "前端申购费(%)", "运作管理费[每年](%)", "券商佣金费率[双向](%)", "免手续费最低持有天数", "最新单位净值", "1周前净值", "1周内最大净值", "1周内最小净值", "1周前同比", "1周内最大同比", "1周内最小同比", "1周盈亏比", "1个月前单位净值", "1个月内最大单位净值", "1个月内最小单位净值", "1个月前同比", "1个月内最大同比", "1个月内最小同比", "1个月盈亏比", "3个月前单位净值", "3个月内最大单位净值", "3个月内最小单位净值", "3个月前同比", "3个月内最大同比", "3个月内最小同比", "3个月盈亏比", "6个月前单位净值", "6个月内最大单位净值", "6个月内最小单位净值", "6个月前同比", "6个月内最大同比", "6个月内最小同比", "6个月盈亏比", "1年前单位净值", "1年内最大单位净值", "1年内最小单位净值", "1年前同比", "1年内最大同比", "1年内最小同比", "1年盈亏比", "2年前单位净值", "2年内最大单位净值", "2年内最小单位净值", "2年同比", "2年内最大同比", "2年内最小同比", "2年盈亏比", "3年前单位净值", "3年内最大单位净值", "3年内最小单位净值", "3年同比", "3年内最大同比", "3年内最小同比", "3年盈亏比", "5年前单位净值", "5年内最大单位净值", "5年内最小单位净值", "5年同比", "5年内最大同比", "5年内最小同比", "5年盈亏比", "创建时间", "最后更新时间", "状态"};
        for (int i = 0; i < headers.length; i++) {
            Cell cell = headerRow.createCell(i);
            cell.setCellValue(headers[i]);
        }

        // 填充数据
        for (int i = 0; i < allFunds.size(); i++) {
            Row row = sheet.createRow(i + 1);
            FundDto fund = allFunds.get(i);
            
            // 处理可能为null的值
            row.createCell(0).setCellValue(fund.getFundCode() != null ? fund.getFundCode() : "");
            row.createCell(1).setCellValue(fund.getFundName() != null ? fund.getFundName() : "");
            
            // 标的类型和子类型映射
            String fundTypeText = getFundTypeText(fund.getFundType());
            String subTypeText = getSubTypeText(fund.getFundType(), fund.getSubType());
            
            row.createCell(2).setCellValue(fundTypeText);
            row.createCell(3).setCellValue(subTypeText);
            
            row.createCell(4).setCellValue(fund.getFrontEndPurchaseFee() != null ? fund.getFrontEndPurchaseFee().doubleValue() : 0);
            row.createCell(5).setCellValue(fund.getAnnualManagementFee() != null ? fund.getAnnualManagementFee().doubleValue() : 0);
            row.createCell(6).setCellValue(fund.getBrokerCommissionRate() != null ? fund.getBrokerCommissionRate().doubleValue() : 0);
            row.createCell(7).setCellValue(fund.getFreeFeeMinDays() != null ? fund.getFreeFeeMinDays() : 0);
            
            row.createCell(8).setCellValue(fund.getNetValue() != null ? fund.getNetValue().doubleValue() : 0);
            row.createCell(9).setCellValue(fund.getNetValue1w() != null ? fund.getNetValue1w().doubleValue() : 0);
            row.createCell(10).setCellValue(fund.getMaxNetValue1w() != null ? fund.getMaxNetValue1w().doubleValue() : 0);
            row.createCell(11).setCellValue(fund.getMinNetValue1w() != null ? fund.getMinNetValue1w().doubleValue() : 0);
            row.createCell(12).setCellValue(fund.getNetValue1wYoy() != null ? fund.getNetValue1wYoy().doubleValue() : 0);
            row.createCell(13).setCellValue(fund.getMaxNetValue1wYoy() != null ? fund.getMaxNetValue1wYoy().doubleValue() : 0);
            row.createCell(14).setCellValue(fund.getMinNetValue1wYoy() != null ? fund.getMinNetValue1wYoy().doubleValue() : 0);
            row.createCell(15).setCellValue(fund.getProfitLossRatio1w() != null ? fund.getProfitLossRatio1w().doubleValue() : 0);
            row.createCell(16).setCellValue(fund.getNetValue1m() != null ? fund.getNetValue1m().doubleValue() : 0);
            row.createCell(17).setCellValue(fund.getMaxNetValue1m() != null ? fund.getMaxNetValue1m().doubleValue() : 0);
            row.createCell(18).setCellValue(fund.getMinNetValue1m() != null ? fund.getMinNetValue1m().doubleValue() : 0);
            row.createCell(19).setCellValue(fund.getNetValue1mYoy() != null ? fund.getNetValue1mYoy().doubleValue() : 0);
            row.createCell(20).setCellValue(fund.getMaxNetValue1mYoy() != null ? fund.getMaxNetValue1mYoy().doubleValue() : 0);
            row.createCell(21).setCellValue(fund.getMinNetValue1mYoy() != null ? fund.getMinNetValue1mYoy().doubleValue() : 0);
            row.createCell(22).setCellValue(fund.getProfitLossRatio1m() != null ? fund.getProfitLossRatio1m().doubleValue() : 0);
            row.createCell(23).setCellValue(fund.getNetValue3m() != null ? fund.getNetValue3m().doubleValue() : 0);
            row.createCell(24).setCellValue(fund.getMaxNetValue3m() != null ? fund.getMaxNetValue3m().doubleValue() : 0);
            row.createCell(25).setCellValue(fund.getMinNetValue3m() != null ? fund.getMinNetValue3m().doubleValue() : 0);
            row.createCell(26).setCellValue(fund.getNetValue3mYoy() != null ? fund.getNetValue3mYoy().doubleValue() : 0);
            row.createCell(27).setCellValue(fund.getMaxNetValue3mYoy() != null ? fund.getMaxNetValue3mYoy().doubleValue() : 0);
            row.createCell(28).setCellValue(fund.getMinNetValue3mYoy() != null ? fund.getMinNetValue3mYoy().doubleValue() : 0);
            row.createCell(29).setCellValue(fund.getProfitLossRatio3m() != null ? fund.getProfitLossRatio3m().doubleValue() : 0);
            row.createCell(30).setCellValue(fund.getNetValue6m() != null ? fund.getNetValue6m().doubleValue() : 0);
            row.createCell(31).setCellValue(fund.getMaxNetValue6m() != null ? fund.getMaxNetValue6m().doubleValue() : 0);
            row.createCell(32).setCellValue(fund.getMinNetValue6m() != null ? fund.getMinNetValue6m().doubleValue() : 0);
            row.createCell(33).setCellValue(fund.getNetValue6mYoy() != null ? fund.getNetValue6mYoy().doubleValue() : 0);
            row.createCell(34).setCellValue(fund.getMaxNetValue6mYoy() != null ? fund.getMaxNetValue6mYoy().doubleValue() : 0);
            row.createCell(35).setCellValue(fund.getMinNetValue6mYoy() != null ? fund.getMinNetValue6mYoy().doubleValue() : 0);
            row.createCell(36).setCellValue(fund.getProfitLossRatio6m() != null ? fund.getProfitLossRatio6m().doubleValue() : 0);
            row.createCell(37).setCellValue(fund.getNetValue1y() != null ? fund.getNetValue1y().doubleValue() : 0);
            row.createCell(38).setCellValue(fund.getMaxNetValue1y() != null ? fund.getMaxNetValue1y().doubleValue() : 0);
            row.createCell(39).setCellValue(fund.getMinNetValue1y() != null ? fund.getMinNetValue1y().doubleValue() : 0);
            row.createCell(40).setCellValue(fund.getNetValue1yYoy() != null ? fund.getNetValue1yYoy().doubleValue() : 0);
            row.createCell(41).setCellValue(fund.getMaxNetValue1yYoy() != null ? fund.getMaxNetValue1yYoy().doubleValue() : 0);
            row.createCell(42).setCellValue(fund.getMinNetValue1yYoy() != null ? fund.getMinNetValue1yYoy().doubleValue() : 0);
            row.createCell(43).setCellValue(fund.getProfitLossRatio1y() != null ? fund.getProfitLossRatio1y().doubleValue() : 0);
            row.createCell(44).setCellValue(fund.getNetValue2y() != null ? fund.getNetValue2y().doubleValue() : 0);
            row.createCell(45).setCellValue(fund.getMaxNetValue2y() != null ? fund.getMaxNetValue2y().doubleValue() : 0);
            row.createCell(46).setCellValue(fund.getMinNetValue2y() != null ? fund.getMinNetValue2y().doubleValue() : 0);
            row.createCell(47).setCellValue(fund.getNetValue2yYoy() != null ? fund.getNetValue2yYoy().doubleValue() : 0);
            row.createCell(48).setCellValue(fund.getMaxNetValue2yYoy() != null ? fund.getMaxNetValue2yYoy().doubleValue() : 0);
            row.createCell(49).setCellValue(fund.getMinNetValue2yYoy() != null ? fund.getMinNetValue2yYoy().doubleValue() : 0);
            row.createCell(50).setCellValue(fund.getProfitLossRatio2y() != null ? fund.getProfitLossRatio2y().doubleValue() : 0);
            row.createCell(51).setCellValue(fund.getNetValue3y() != null ? fund.getNetValue3y().doubleValue() : 0);
            row.createCell(52).setCellValue(fund.getMaxNetValue3y() != null ? fund.getMaxNetValue3y().doubleValue() : 0);
            row.createCell(53).setCellValue(fund.getMinNetValue3y() != null ? fund.getMinNetValue3y().doubleValue() : 0);
            row.createCell(54).setCellValue(fund.getNetValue3yYoy() != null ? fund.getNetValue3yYoy().doubleValue() : 0);
            row.createCell(55).setCellValue(fund.getMaxNetValue3yYoy() != null ? fund.getMaxNetValue3yYoy().doubleValue() : 0);
            row.createCell(56).setCellValue(fund.getMinNetValue3yYoy() != null ? fund.getMinNetValue3yYoy().doubleValue() : 0);
            row.createCell(57).setCellValue(fund.getProfitLossRatio3y() != null ? fund.getProfitLossRatio3y().doubleValue() : 0);
            row.createCell(58).setCellValue(fund.getNetValue5y() != null ? fund.getNetValue5y().doubleValue() : 0);
            row.createCell(59).setCellValue(fund.getMaxNetValue5y() != null ? fund.getMaxNetValue5y().doubleValue() : 0);
            row.createCell(60).setCellValue(fund.getMinNetValue5y() != null ? fund.getMinNetValue5y().doubleValue() : 0);
            row.createCell(61).setCellValue(fund.getNetValue5yYoy() != null ? fund.getNetValue5yYoy().doubleValue() : 0);
            row.createCell(62).setCellValue(fund.getMaxNetValue5yYoy() != null ? fund.getMaxNetValue5yYoy().doubleValue() : 0);
            row.createCell(63).setCellValue(fund.getMinNetValue5yYoy() != null ? fund.getMinNetValue5yYoy().doubleValue() : 0);
            row.createCell(64).setCellValue(fund.getProfitLossRatio5y() != null ? fund.getProfitLossRatio5y().doubleValue() : 0);
            row.createCell(65).setCellValue(fund.getCreatedTime() != null ? fund.getCreatedTime() : "");
            row.createCell(66).setCellValue(fund.getUpdatedTime() != null ? fund.getUpdatedTime() : "");
            row.createCell(67).setCellValue(fund.getStatus() != null ? fund.getStatus() : "");
        }

        // 设置响应头
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setHeader("Content-Disposition", "attachment; filename=funds.xlsx");

        // 将工作簿写入响应输出流
        try (OutputStream outputStream = response.getOutputStream()) {
            workbook.write(outputStream);
            logger.info("基金数据导出成功，共导出{}条记录", allFunds.size());
        } catch (IOException e) {
            logger.error("基金数据导出失败", e);
            e.printStackTrace();
        } finally {
            try {
                workbook.close();
            } catch (IOException e) {
                logger.error("关闭Excel工作簿失败", e);
                e.printStackTrace();
            }
        }
    }
    
    // 标的类型映射
    private String getFundTypeText(String fundType) {
        if (fundType == null) return "";
        
        switch (fundType) {
            case "1": return "稳健灵活";
            case "2": return "黄金";
            case "3": return "基金";
            case "4": return "股票";
            case "5": return "ETF";
            default: return "未知";
        }
    }
    
    // 子类型映射
    private String getSubTypeText(String fundType, String subType) {
        if (fundType == null || subType == null) return "";
        
        String fullType = fundType + "_" + subType;
        
        switch (fullType) {
            // 稳健灵活子类型 (标的类型为1)
            case "1_11": return "余额宝";
            case "1_12": return "余利宝";
            case "1_13": return "月利宝";
            
            // 黄金子类型 (标的类型为2)
            case "2_21": return "工行积存金";
            
            // 基金子类型 (标的类型为3)
            case "3_31": return "指数基金";
            case "3_32": return "偏债基金";
            case "3_33": return "偏股基金";
            case "3_34": return "全球基金";
            case "3_35": return "黄金基金";
            
            // 股票子类型 (标的类型为4)
            case "4_41": return "主板股票";
            case "4_42": return "创业板股票";
            case "4_43": return "科创板股票";
            case "4_44": return "北证股票";
            case "4_45": return "港交所股票";
            
            // ETF子类型 (标的类型为5)
            case "5_51": return "大盘ETF";
            case "5_52": return "行业ETF";
            case "5_53": return "策略ETF";
            
            default: return "未知";
        }
    }
}